require 'rubygems'
require 'zip/zip'
require 'rexml/document'
require 'fileutils'

module Installr::Client::Command
  class Build < Base
    def checkout(build_system, target_rule)
      puts "[build:checkout] make checkout using #{build_system} #{target_rule}" if @options[:verbose]
      @log.info("make checkout using #{build_system} #{target_rule}")
      build_result = ''

      cmd = case build_system.downcase
        when "ant" then build_system + " -s " + @options[:build_path] + " " +  target_rule + " 2>&1"
	when "mvn" then build_system + " -f " + @options[:build_path] + "/pom.xml " + target_rule + " 2>&1"
	#when "gradle" then build_system + " -p " + @options[:build_path] + " " +  target_rule + " 2>&1"
	when "hg" then build_system + " --cwd " + @options[:build_path] + " " +  target_rule + " 2>&1"
	when "git" then build_system + " --git-dir=" + @options[:build_path] + "/.git" + " " +  target_rule + " 2>&1"
	when "svn" then build_system + " " + target_rule + " " + @options[:build_path] + " 2>&1"
	else puts "[build:checkout] build_system should be one of { ant, mvn, hg, git, svn }"; @log.error("[build:checkout] build_system should be one of { ant, mvn, hg, git, svn }"); return -1
      end

      puts "cmd: #{cmd}" if @options[:verbose]

      STDOUT.sync = true
      IO.popen(cmd) do |pipe|
        pipe.sync = true
        while str = pipe.gets
	    puts str
	end
      end
      return 0
    end

    def make(build_system, target_rule)
      puts "[build:make] make build using #{build_system} #{target_rule}" if @options[:verbose]
      @log.info("[build:make] make build using #{build_system} #{target_rule}")
      build_result = ''

      cmd = case build_system.downcase
        when "ant" then "ant -f " + @options[:build_path] + "/build.xml " +  target_rule + " 2>&1"
	when "mvn" then "mvn -f " + @options[:build_path] + "/pom.xml " + target_rule + " 2>&1"
	#when "gradle" then "gradle -p " + @options[:build_path] + " " +  target_rule + " 2>&1"
	else puts "[build:make] build_system should be one of { ant, mvn }";  @log.error("[build:make] build_system should be one of { ant, mvn }"); return -1
      end

      puts "cmd: #{cmd}" if @options[:verbose]

      STDOUT.sync = true
      IO.popen(cmd) do |pipe|
        pipe.sync = true
        while str = pipe.gets
          case build_system.downcase
	    when "ant" 
              if str.include?("[war]")
                build_result = str
              end
	    when "mvn"
              if str.include?("[INFO] Installing")
                build_result += str;
                break
              end
	    else return -1
          end
	end
      end

      if build_result != '' && @options[:no_depend] == false
        # 1. copy installr.xml to base dir
        installr_xml = File.expand_path('../../../../lib/share/client/installr.xml', __FILE__)
	FileUtils.copy installr_xml, @options[:build_path] + "/installr.xml"

        # 2. if mvn, convert pom to ivy
	if build_system.downcase == "mvn"
	  cmd = "ant -f " + @options[:build_path] + "/installr.xml convert" + " 2>&1"

          puts "cmd: #{cmd}" if @options[:verbose]

          IO.popen(cmd) do |pipe|
            pipe.sync = true
            while str = pipe.gets
  	      puts str
            end
	  end
	end

        # 3. parsing artifact report
	if build_system.downcase == "ant"
	  cmd = "ant -f " + @options[:build_path] + "/installr.xml report" + " 2>&1"
          puts "cmd: #{cmd}" if @options[:verbose]
	elsif build_system.downcase == "mvn"
	  cmd = build_system + " -f " + @options[:build_path] + "/pom.xml dependency:list -DoutputFile=artifactreport.txt" + " 2>&1"
          puts "cmd: #{cmd}" if @options[:verbose]
	end

        IO.popen(cmd) do |pipe|
          pipe.sync = true
          while str = pipe.gets
            puts str
	  end
	end

	locs = []
	if build_system.downcase == "ant"
	  xml_data = File.read(@options[:build_path] + "/artifactreport.xml")
	  doc = REXML::Document.new(xml_data)
          doc.elements.each('modules/module/artifact/retrieve-location') { |element| locs << element.text }
	elsif build_system.downcase == "mvn"
	  f = File.open(@options[:build_path] + "/artifactreport.txt", "r")
	  f.each_line do |line|
            columns = line.split(/: */)
            if columns.length == 5
              if (columns[4].chomp == 'provided') or (columns[4].chomp == 'test')
                next
              else
                locs << "lib/" + columns[1]+"-"+columns[3]+"."+columns[2]
              end
	    end
	  end
	  f.close
	end

        if (RbConfig::CONFIG['target_os'] == "mswin32") or (RbConfig::CONFIG['target_os'] == "mingw32")
          path_delimiter = '\\'
        else
          path_delimiter = '/'
        end

        # 4. remove dependencies from the target war file
        war_file = case build_system.downcase
	  when "ant" then @options[:build_path] + path_delimiter + build_result.split(path_delimiter).last.chomp
	  when "mvn" then @options[:build_path] + path_delimiter + "target" + path_delimiter + build_result.split(path_delimiter).last.chomp
	  else return -1;
        end

        unless File.exist?(war_file)
          puts "[build:make] cannot find warfile #{war_file}"
          @log.error("[build:make] cannot find warfile #{war_file}")
          return -1
        end

	Zip::ZipFile.open(war_file) {
	  |zipfile|
	  locs.each { |filename| zipfile.remove("WEB-INF/" + filename) }
          build_xml = File.expand_path('../../../../lib/share/server/build.xml', __FILE__)
          ivysettings_xml = File.expand_path('../../../../lib/share/server/ivysettings.xml', __FILE__)
	  zipfile.add("WEB-INF/build.xml", build_xml)
	  zipfile.add("WEB-INF/ivysettings.xml", ivysettings_xml)
	  zipfile.add("WEB-INF/ivy.xml", @options[:build_path] + "/ivy.xml")
	}

	# 5. cleanup
	FileUtils.remove @options[:build_path] + "/installr.xml"
        cmd = case build_system.downcase
          when "ant" then FileUtils.remove @options[:build_path] + "/artifactreport.xml"
	  when "mvn" then FileUtils.remove @options[:build_path] + "/artifactreport.txt"; FileUtils.remove @options[:build_path] + "/ivy.xml"
        end
      elsif build_result != '' && @options[:no_depend] == true
        return 0
      else
        puts "[build:make] cannot build warfile #{war_file}"
        @log.error("[build:make] cannot build warfile")
        return -1
      end
      puts "[build: make] remove dependencies from the warfile #{war_file}" if @options[:verbose]
      return 0
    end
  end
end
